home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / P4⁄Mac 2.0d4 / Mac source 2.0 / TransDisplay.p < prev    next >
Encoding:
Text File  |  1996-09-28  |  28.5 KB  |  1,101 lines  |  [TEXT/PJMM]

  1. {    TransDisplay version 1.0 - TransSkel plug-in module supporting}
  2. {    an arbitrary number of generic display windows with memory.}
  3.  
  4. {    TransSkel and TransDisplay are public domain, and are written by:}
  5.  
  6. {            Paul DuBois}
  7. {            Wisconsin Regional Primate Research Center}
  8. {            1220 Capital Court}
  9. {            Madison WI  53706  USA}
  10.  
  11. {    UUCP:        [allegra,ihnp4,seismo]!uwvax !uwmacc !dubois }
  12. {    ARPA :     dubois @ unix.macc.wisc.edu }
  13. {                dubois @ rhesus.primate.wisc.edu }
  14.  
  15. {    The Pascal Version of TransSkel is public domain and was ported by        }
  16.  
  17. {            Owen Hartnett            }
  18. {            Ωhm Software            }
  19. {            163 Richard Drive        }
  20. {            Tiverton, RI 02878        }
  21.  
  22. {    CSNET:    omh@cs.brown.edu.CSNET                                             }
  23. {    ARPA:        omh%cs.brown.edu@relay.cs.net-relay.ARPA                        }
  24. {    UUCP:        [ihnp4,allegra]!brunix !omh                                            }
  25.  
  26. {    Psychic Wavelength:  182.2245 Meters  (sorry, couldn't resist)    }
  27.  
  28. {    This version of TransDisplay written for Lightspeed Pascal.  Lightspeed Pascal}
  29. {    is a trademark of:}
  30. {            THINK Technologies, Inc}
  31. {            420 Bedford Street  Suite 350}
  32. {            Lexington, MA  02173  USA}
  33.  
  34.  
  35.  { History}
  36. {  08/25/86    Genesis.  Beta version.}
  37. {  09/15/86    Changed to allow arbitrary number of windows.  Changed}
  38. {             version number to 1.0.}
  39. {  01/10/87    Ported to LightSpeed Pascal by Owen Hartnett                }
  40. {    Ωhm Software, 163 Richard Drive, Tiverton, RI 02878                }
  41. {  12/2/88    Made changes to add conditional compiling if you only need }
  42. {            one TransDisplay window.  Set the following cond variable        }
  43. {            singleDisplay to true if you want only one TransDisplay window }
  44. {            and want smaller code size.    Made adjustments for LSP 2.0    }
  45.  
  46. {dec -94: Two seriou bugs fixed by Ingemar R, both causing problems with multiple TransDisplay windows:}
  47. {– Mouse events could be sent to the wrong display window.}
  48. {– SyncGlobals didn't check dispInfo for nil, which could cause crashes.}
  49.  
  50. unit TransDisplay;
  51.  
  52. interface
  53.  
  54. {$SETC singleDisplay:=false }
  55.     uses
  56. {$IFC UNDEFINED THINK_PASCAL}
  57.         Types, QuickDraw, Windows, Dialogs, ToolUtils, Events, Controls, {}
  58.         Memory, Sound, OSUtils, MixedMode,
  59. {$IFC GENERATINGPOWERPC}
  60.         PPCTransSkelCallProcs, 
  61. {$ENDC}
  62. {$ELSEC}
  63. {$SETC GENERATINGPOWERPC:=false }
  64.         InterfacesUI,
  65. {$ENDC}
  66.         TransSkel;
  67.  
  68.     procedure SetDWindow (theWind: WindowPtr);
  69.     procedure DisplayString (theStr: str255);
  70.     procedure DisplayHexLong (l: longint);
  71.     procedure DisplayHexInt (i: integer);
  72.     procedure DisplayHexChar (c: char);
  73.     procedure DisplayBoolean (b: Boolean);
  74.     procedure DisplayChar (c: char);
  75.     procedure DisplayInt (i: integer);
  76.     procedure DisplayLong (l: longint);
  77.     procedure DisplayLn;
  78.     procedure DisplayText (theText: Ptr; len: longint);
  79.     function GetNewDWindow (resourceNum: integer; behind: WindowPtr): WindowPtr;
  80.     function NewDWindow (bounds: Rect; title: Str255; visible: Boolean; behind: WindowPtr; goAway: Boolean; refcon: longint): WindowPTr;
  81.     procedure FlushDWindow (theWind: WindowPtr; byteCount: longint);
  82.     procedure GetDWindow (var theWind: WindowPtr);
  83.     procedure SetDWindowFlush (theWind: WindowPtr; maxText, flushAmt: longint);
  84.     procedure SetDWindowNotify (theWind: WindowPTr; p: ProcPtr);
  85.     procedure SetDWindowPos (theWind: WindowPtr; lineNum: integer);
  86.     procedure SetDWindowStyle (theWind: WindowPtr; font, size, wrap, just: integer);
  87.     function GetDWindowTE (theWind: WindowPtr): TEHandle;
  88.     function IsDWindow (theWind: WindowPtr): Boolean;
  89.     procedure TransDisplayInit;
  90.  
  91. implementation
  92.  
  93. {    Display window types, constants, variables.}
  94.  
  95.     const
  96.         monaco = 4;
  97.  
  98. {$IFC not singleDisplay }
  99.     type
  100.         DIPtr = ^DisplayInfo;
  101.         DIHandle = ^DIPtr;
  102.         DisplayInfo = record
  103.                 dWind: WindowPtr;        { display window         }
  104.                 dTE: TEHandle;            { window text            }
  105.                 dScroll: ControlHandle;    { window scroll bar      }
  106.                 dActivate: ProcPtr;        { notification procedure }
  107.                 dMaxText: longint;        { max text length        }
  108.                 dFlushAmt: longint;        { amount to autoflush    }
  109.                 dNext: DIHandle;            { next window structure  }
  110.             end;
  111. {$ENDC}
  112.  
  113.     var
  114.  
  115. { Look at TransDisplayInit procedure for initial values of these variables    }
  116.  
  117.         d_font, d_size: integer;                    { default font              }
  118.                                                 { default pointsize         }
  119.         d_wrap, d_just: integer;                { default word wrap (on)    }
  120.                                                 { default justification     }
  121.         d_maxText, d_flushAmt: longint;        { default max text allowed  }
  122.                                                 { default autoflush amount  }
  123.         d_activate: ProcPtr;                    { default notification proc }
  124.  
  125. {    Lowest allowable values for autoflush characteristics}
  126.  
  127.  
  128.         d_loMaxText, d_loFlushAmt: longint;
  129.  
  130. {$IFC not singleDisplay }
  131.  
  132.         dwList: DIHandle;
  133.  
  134. {    Variables pertaining to the display window being operated on}
  135. {    (updated, resized, etc.).  This window is not necessarily the}
  136. {    same as curDispWind!  These variables are synced to the window}
  137. {    with SyncGlobals. }
  138.  
  139.         dispInfo: DIHandle;        { info structure         }
  140. {$ENDC}
  141.  
  142.         dispWind: WindowPtr;            { the window             }
  143.         dispTE: TEHandle;                { window text            }
  144.         dispScroll: ControlHandle;        { the scroll bar         }
  145.         dActivate: ProcPtr;                { notification procedure }
  146.         dMaxText, dFlushAmt: longint;        { max text allowed       }
  147.         { amount to flush        }
  148.  
  149. {    curDispWind is the current output window.}
  150. {    If curDispWind = nil, output is turned off.}
  151.  
  152.         curDispWind: WindowPtr;
  153.  
  154. { -------------------------------------------------------------------- }
  155. {                Miscellaneous Internal (private) Routines                }
  156. { -------------------------------------------------------------------- }
  157.  
  158.  
  159.  
  160. {    Draw grow box of dispWind in lower right hand corner}
  161.  
  162.     procedure DrawGrowBox;
  163.  
  164.         var
  165.             oldClip: RgnHandle;
  166.             r: Rect;
  167.  
  168.     begin
  169.         r := dispWind^.portRect;
  170.         r.left := r.right - 15;        { draw only in corner }
  171.         r.top := r.bottom - 15;
  172.         oldClip := NewRgn;
  173.         GetClip(oldClip);
  174.         ClipRect(r);
  175.         DrawGrowIcon(dispWind);
  176.         SetClip(oldClip);
  177.         DisposeRgn(oldClip);
  178.     end;
  179.  
  180.  
  181.  
  182.  
  183. { -------------------------------------------------------------------- }
  184. {            Lowest-level Internal (Private) Display Window Routines        }
  185. { -------------------------------------------------------------------- }
  186.  
  187. {$IFC not singleDisplay}
  188.  
  189. {    Get display window info associated with window.}
  190. {    Return nil if window isn't a known display window.}
  191.  
  192.     function GetDInfo (theWind: WindowPtr): DIHandle;
  193.         var
  194.             h: DIHandle;
  195.             foundit: Boolean;
  196.     begin
  197.         h := dwList;
  198.         foundit := false;
  199.         while (h <> nil) and not foundit do
  200.             begin
  201.                 if h^^.dWind = theWind then
  202.                     begin
  203.                         GetDInfo := h;
  204.                         h := nil;
  205.                         foundit := true;
  206.                     end
  207.                 else
  208.                     h := h^^.dNext;
  209.             end;
  210.         if not foundit then
  211.             GetDInfo := nil;                    {make it a nop    }
  212.     end;
  213. {$ENDC}
  214.  
  215. {$IFC singleDisplay}
  216.  
  217.     procedure SyncGlobals (theWind: WindowPtr);
  218.     begin
  219.     end;            { make it a nop }
  220.  
  221. {$ELSEC }
  222. {    Synchronize globals to a display window.  theWind must be a legal}
  223. {    display window, with one exception:  if theWind is nil, the}
  224. {    variables are synced to the current port.  That is safe (and}
  225. {    correct) because:}
  226. {    (i)     nil is only passed by display window handler procedures,}
  227. {         which are only called by TransSkel for display window}
  228. {         events.}
  229. {    (ii) TransSkel always sets the port to the window before}
  230. {         calling the handler proc. <- NO LONGER TRUE!}
  231. {    Hence, use of the current port under these circumstances}
  232. {    always produces a legal display window.}
  233.  
  234. {    SyncGlobals is not used in single display mode, because the}
  235. {    globals are all set by SetupDWindow and do not change thereafter.}
  236.  
  237.     procedure SyncGlobals (theWind: WindowPtr);
  238.  
  239.         var
  240.             dp: DIPtr;
  241.     begin
  242.         if theWind = nil then                    { use current window }
  243.             GetPort(theWind);
  244.         dispWind := theWind;
  245.         dispInfo := GetDInfo(dispWind);
  246. {Bugfix by Ingemar 941208: The current port might not be a display window!}
  247.         if dispInfo <> nil then
  248.             begin
  249.                 dp := dispInfo^;
  250.                 dispScroll := dp^.dScroll;
  251.                 dispTE := dp^.dTE;
  252.                 dActivate := dp^.dActivate;
  253.                 dMaxText := dp^.dMaxText;
  254.                 dFlushAmt := dp^.dFlushAmt;
  255.             end;
  256.     end;
  257. {$ENDC}
  258.  
  259. {    Calculate the dimensions of the editing rectangle for}
  260. {    dispWind (which must be set properly and is assumed to }
  261. {    the current port).  (The viewRect and destRect are the}
  262. {    same size .) Assumes the port , text font and text size are all}
  263. {    set properly.  The viewRect is sized so that an integral}
  264. {    number of lines can be displayed in it, i.e., so that a}
  265. {    partial line never shows at the bottom. }
  266.  
  267.     procedure CalcEditRect (var r: Rect);
  268.  
  269.         var
  270.             f: FontInfo;
  271.             lineHeight: integer;
  272.  
  273.     begin
  274.         GetFontInfo(f);
  275.         lineHeight := f.ascent + f.descent + f.leading;
  276.         r := dispWind^.portRect;
  277.         r.left := r.left + 4;
  278.         r.right := r.right - 17;            { leave room for scroll bar + 2 }
  279.         r.top := r.top + 2;
  280.         r.bottom := r.top + ((r.bottom - (r.top - 2)) div lineHeight) * lineHeight;
  281.     end;
  282.  
  283. {    Calculate the dimensions of the scroll bar rectangle for the}
  284. {    window.  Make sure that the edges overlap the window frame and}
  285. {    the grow box.}
  286.  
  287.     procedure CalcScrollRect (var r: Rect);
  288.  
  289.     begin
  290.         r := dispWind^.portRect;
  291.         r.right := r.right + 1;
  292.         r.left := r.right - 16;
  293.         r.top := r.top - 1;
  294.         r.bottom := r.bottom - 14;
  295.     end;
  296.  
  297. {    Calculate the number of lines currently scrolled off}
  298. {    the top.}
  299.  
  300.     function LinesOffTop: integer;
  301.  
  302.         var
  303.             ePtr: TEPtr;
  304.  
  305.     begin
  306.         ePtr := dispTE^;
  307.         LinesOffTop := (ePtr^.viewRect.top - ePtr^.destRect.top) div ePtr^.lineHeight;
  308.     end;
  309.  
  310. {    Highlight the scroll bar properly.  This means that it's not}
  311. {    made active if the window itself isn't active, even if}
  312. {    there's enough text to fill the window. }
  313.  
  314.     procedure HiliteScroll;
  315.         var
  316.             result: integer;
  317.     begin
  318.         if (GetControlMaximum(dispScroll) > 0) and (dispWind = FrontWindow) then
  319.             result := 0
  320.         else
  321.             result := 255;
  322.         HiliteControl(dispScroll, result);
  323.     end;
  324.  
  325. {    Scroll to the correct position.  lDelta is the}
  326. {    amount to CHANGE the current scroll setting by.}
  327. {    Positive scrolls the text up, negative down.}
  328.  
  329.     procedure ScrollText (lDelta: integer);
  330.  
  331.         var
  332.             lHeight, newLine, topLine: integer;
  333.  
  334.     begin
  335.         lHeight := dispTE^^.lineHeight;
  336.         topLine := LinesOffTop;
  337.         newLine := topLine + lDelta;
  338.         if newLine < 0 then
  339.             newLine := 0;
  340.         if newLine > GetControlMaximum(dispScroll) then
  341.             newLine := GetControlMaximum(dispScroll);
  342.         SetControlValue(dispScroll, newLine);
  343.         TEScroll(0, (topLine - newLine) * lHeight, dispTE);
  344.     end;
  345.  
  346.  
  347. {    Filter proc for tracking mousedown in scroll bar . The code}
  348. {    for the part originally hit is stored in the control 's reference}
  349. {    value by Mouse ( ) before calling this . }
  350.  
  351.  
  352. {    Scroll by one line if the mouse is in an arrow.  Scroll by a half}
  353. {    window's worth of lines if the mouse is in a page region. }
  354.  
  355.     procedure TrackScroll (theScroll: ControlHandle; partCode: integer);
  356.  
  357.         var
  358.             lDelta, halfPage: integer;
  359.  
  360.     begin
  361.         if partCode = GetControlReference(theScroll) then        { still in same part? }
  362.             begin
  363.                 halfPage := ((dispTE^^.viewRect.bottom - dispTE^^.viewRect.top) div dispTE^^.lineHeight) div 2;
  364.                 if halfPage = 0 then
  365.                     halfPage := halfPage + 1;
  366.                 case partCode of
  367.                     kControlUpButtonPart: 
  368.                         lDelta := -1;
  369.                     kControlDownButtonPart: 
  370.                         lDelta := 1;
  371.                     kControlPageUpPart: 
  372.                         lDelta := -halfPage;
  373.                     kControlPageDownPart: 
  374.                         lDelta := halfPage;
  375.                     otherwise
  376.                 end;
  377.                 ScrollText(lDelta);
  378.             end;
  379.     end;
  380.  
  381. {    Adjust the text in the text record and the scroll bar.  This is}
  382. {    called for major catastrophes, such as resizing the window, or}
  383. {    changing the word wrap style.  It makes sure the view and}
  384. {    destination rectangles are sized properly, and that the bottom}
  385. {    line of text never scrolls up past the bottom line of the}
  386. {    window, if there's enough to fill the window, and that the}
  387. {    scroll bar max and current values are set properly.}
  388.  
  389. {    Resizing the dest rect just means resetting the right edge}
  390. {    (the top is NOT reset), since text might be scrolled off the}
  391. {    top (i.e., destRect.top != 0).}
  392.  
  393.     procedure OverhaulDisplay;
  394.  
  395.         var
  396.             r: Rect;
  397.             nLines, visLines, topLines, scrollLines, lHeight: integer;
  398.             { number of lines in TERec }
  399.         { number of lines displayable in window }
  400.         { number of lines currently scrolled off top }
  401.         { number of lines to scroll down }
  402.  
  403.     begin
  404.         CalcEditRect(r);
  405.         dispTE^^.destRect.right := r.right;
  406.         dispTE^^.viewRect := r;
  407.         TECalText(dispTE);        { recalc line starts }
  408.         lHeight := dispTE^^.lineHeight;
  409.         nLines := dispTE^^.nLines;
  410.         visLines := (r.bottom - r.top) div lheight;
  411.         topLines := LinesoffTop;
  412.  
  413. {    If the text doesn't fill the window (visLines > nLines - topLines),}
  414. {    pull the text down if possible (if topLines > 0).  Make sure}
  415. {    not to try to scroll down by more lines than are hidden off the top .}
  416.  
  417.         scrollLines := visLines - (nLines - topLines);
  418.         if (scrollLines > 0) and (topLines > 0) then
  419.             begin
  420.                 if scrollLines > topLines then
  421.                     scrollLines := topLines;
  422.                 TEScroll(0, scrollLInes * lHeight, dispTE);
  423.                 toplines := topLines - scrollLines;
  424.             end;
  425.         TEUpdate(r, dispTE);
  426.         if nLines - visLines < 0 then
  427.             SetControlMaximum(dispScroll, 0)
  428.         else
  429.             SetControlMaximum(dispScroll, nLines - VisLines);
  430.         SetControlValue(dispScroll, topLines);
  431.         HiliteScroll;
  432.     end;
  433.  
  434. {$IFC GENERATINGPOWERPC = false}
  435.     procedure callpnoarg (myProc: ProcPtr);
  436. { For all the Procedures that are called with no arguments                        }
  437.     inline
  438.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  439.         $4e90;
  440.  
  441.     procedure callpBoolean (myBool: Boolean; myProc: ProcPtr);
  442. { Two calls use Booleans as one parameter arguments.  This procedure handles    }
  443. { both of them.                                                                    }
  444.     inline
  445.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  446.         $4e90;
  447. {$ENDC}
  448.  
  449. { ---------------------------------------------------------------- }
  450. {                        Window Handler Routines                        }
  451. { ---------------------------------------------------------------- }
  452.  
  453.  
  454.  
  455. {    When the window comes active, highlight the scroll bar appropriately.}
  456. {    When the window is deactivated, un-highlight the scroll bar.}
  457. {    Redraw the grow box.}
  458.  
  459. {    Notify the host as appropriate.}
  460.  
  461. {    Note that clicking close box hides the window, which generates a}
  462. {    deactivate event, so there is no need for a close notifier.}
  463.  
  464.  
  465.     procedure Activate (isActive: Boolean);
  466.  
  467.     begin
  468.         SyncGlobals(nil);                { sync to current port }
  469.         DrawGrowBox;
  470.         HiliteScroll;
  471.  
  472.         if dActivate <> nil then
  473.             callpBoolean(isActive, dActivate);
  474.     end;
  475.  
  476. {    Update window.  The update event might be in response to a}
  477. {    window resizing.  If so, move and resize the scroll bar,}
  478. {    and recalculate the text display.}
  479.  
  480. {    The ValidRect call is done because the HideControl adds the}
  481. {    control bounds box to the update region - which would generate}
  482. {    another update event!  Since everything is redrawn below anyway,}
  483. {    the ValidRect is used to cancel the update.}
  484.  
  485.     procedure Update (resized: Boolean);
  486.  
  487.         var
  488.             r: Rect;
  489.  
  490.     begin
  491.         SyncGlobals(nil);                    { sync to current port }
  492.         r := dispWind^.portRect;
  493.         EraseRect(r);
  494.         if resized then
  495.             begin
  496.                 HideControl(dispScroll);
  497.                 r := dispScroll^^.contrlRect;
  498.                 ValidRect(r);
  499.                 CalcScrollRect(r);
  500.                 SizeControl(dispScroll, 16, r.bottom - r.top);
  501.                 MoveControl(dispScroll, r.left, r.top);
  502.                 OverHaulDisplay;
  503.                 ShowControl(dispScroll);
  504.             end
  505.         else
  506.             begin
  507.                 r := dispTE^^.viewRect;
  508.                 TEUpdate(r, dispTE);
  509.             end;
  510.         DrawGrowBox;
  511.         DrawControls(dispWind);    { redraw scroll bar }
  512.     end;
  513.  
  514. {    Handle mouse clicks in window}
  515.  
  516.     procedure Mouse (thePt: Point; t: longint; mods: integer);
  517.  
  518.         var
  519.             thePart: integer;
  520.             oldCtlValue: integer;
  521.     begin
  522.         SyncGlobals(nil);                    { Sync to current port    }
  523.  
  524.         thePart := TestControl(dispScroll, thePt);
  525.         if thePart = kControlIndicatorPart then
  526.             begin
  527.                 OldCtlValue := GetControlValue(dispScroll);
  528.                 if TrackControl(dispScroll, thePt, nil) = kControlIndicatorPart then
  529.                     ScrollText(GetControlValue(dispScroll) - oldCtlValue);
  530.             end
  531.         else if thePart <> 0 then
  532.             begin
  533.                 SetControlReference(dispScroll, longint(thePart));
  534.                 oldCtlValue := TrackControl(dispScroll, thePt, @TrackScroll);
  535.             end;
  536.     end;
  537.  
  538. {    Remove the display window from the list, and dispose of it.}
  539. {    Since the clobber procedure is never called except for real display}
  540. {    windows, and since the list must therefore be non-empty, it is}
  541. {    not necessary to check the legality of the window or that the}
  542. {    window's in the list.}
  543.  
  544. {    Must do SetDWindow (nil) to turn output off, if the window being}
  545. {    clobbered is the current output window.}
  546.  
  547.     procedure Clobber;
  548.  
  549.         var
  550. {$IFC not singleDisplay}
  551.             h, h2: DIHandle;
  552. {$ENDC}
  553.             keepgoing: Boolean;
  554.  
  555.     begin
  556.         SyncGlobals(nil);                    { sync to current port }
  557.         if dispWind = curDispWind then    { is it the first window in list? }
  558.             SetDWindow(nil);
  559. {$IFC not singleDisplay}
  560.         if dwList^^.dWind = dispWind then    { found it }
  561.             begin
  562.                 h2 := dwList;
  563.                 dwList := dwList^^.dNext;
  564.             end
  565.         else
  566.             begin
  567.                 h := dwList;
  568.                 keepgoing := true;
  569.                 while (h <> nil) and keepgoing do
  570.                     begin
  571.                         h2 := h^^.dNext;
  572.                         if h2^^.dWind = dispWind then
  573.                             begin
  574.                                 h^^.dNext := h2^^.dNext;
  575.                                 keepgoing := false;
  576.                             end;
  577.                         h := h2;
  578.                     end;
  579.             end;
  580.         DisposeHandle(Handle(h2));        { get rid of information structure }
  581. {$ENDC}
  582.         TEDispose(dispTE);                { toss text record }
  583.         DisposeWindow(dispWind);        { toss window and scroll bar }
  584.         dispWind := nil;
  585.     end;
  586.  
  587. { ---------------------------------------------------------------- }
  588. {                            Control Routines                        }
  589. { ---------------------------------------------------------------- }
  590.  
  591.  
  592. {    Test whether a window is a legal display window or not }
  593.  
  594.     function IsDWindow;
  595.  
  596.     begin
  597. {$IFC singleDisplay}
  598.         IsDWindow := (theWind = dispWind) and (dispWind <> nil);
  599. {$ELSEC}
  600.         IsDWindow := GetDInfo(theWind) <> nil;
  601. {$ENDC}
  602.     end;
  603.  
  604. {    Return handle to display window's text record}
  605.  
  606.     function GetDWindowTE;
  607.  
  608. {$IFC not singleDisplay}
  609.  
  610.         var
  611.             dInfo: DIHandle;
  612. {$ENDC}
  613.  
  614.     begin
  615. {$IFC not singleDisplay}
  616.  
  617. {Fix by Ingemar -94: The following line was missing in the 2.0 release:}
  618.         dInfo := GetDInfo(theWind);
  619.  
  620.         if dInfo = nil then {GetDInfo(theWind)}
  621.             GetDWindowTE := nil
  622.         else
  623.             GetDWIndowTE := dInfo^^.dTE;
  624. {$ELSEC}
  625.         if ISDWindow(theWind) then
  626.             GetDWindowTE := dispTE
  627.         else
  628.             GetDWindowTE := nil;
  629. {$ENDC}
  630.     end;
  631.  
  632. {    Change the text display characteristics of a display window}
  633. {    and redisplay it.  As a side effect, this always scrolls to the}
  634. {    home position.}
  635.  
  636.     procedure SetDWindowStyle;
  637.  
  638.         var
  639.             savePort: GrafPtr;
  640.             f: FontInfo;
  641.             te: TEHandle;
  642.             r: Rect;
  643.  
  644.     begin
  645.         if theWind = nil then            { reset window creation defaults }
  646.             begin
  647.                 d_font := font;
  648.                 d_size := size;
  649.                 d_wrap := wrap;
  650.                 d_just := just;
  651.             end
  652.         else
  653.             begin
  654.                 if IsDWindow(theWind) then
  655.                     begin
  656.                         GetPort(savePort);
  657.                         SyncGlobals(theWind);
  658.                         SetPort(dispWind);
  659.                         te := dispTE;
  660.                         r := te^^.viewRect;
  661.                         EraseRect(r);
  662.                         r := te^^.destRect;    { scroll home without redrawing }
  663.  
  664.                         OffsetRect(r, 0, 2 - r.top);
  665.                         te^^.destRect := r;
  666.                         te^^.crOnly := wrap;    { set word wrap }
  667.                         TESetAlignment(just, te);    { set justification TESetJust}
  668.                         TextFont(font);         { set the font and point size }
  669.                         TextSize(size);        { of text record (this is the }
  670.                         GetFontInfo(f);        { hard part) }
  671.                         te^^.lineHeight := f.ascent + f.descent + f.leading;
  672.                         te^^.fontAscent := f.ascent;
  673.                         te^^.txFont := font;
  674.                         te^^.txSize := size;
  675.  
  676.                         OverhaulDisplay;
  677.                         SetPort(savePort);
  678.                     end;
  679.             end;
  680.     end;
  681.  
  682. {    Scroll the text in the window so that line lineNum is at the top.}
  683. {    First line is line zero.}
  684.  
  685.     procedure SetDWindowPos;
  686.  
  687.         var
  688.             savePort: GrafPtr;
  689.  
  690.     begin
  691.         if IsDWindow(theWind) then
  692.             begin
  693.                 GetPort(savePort);
  694.                 SyncGlobals(theWind);
  695.                 SetPort(dispWind);
  696.                 ScrollText(lineNum - GetControlValue(dispScroll));
  697.                 SetPort(savePort);
  698.             end;
  699.     end;
  700.  
  701. {    Set display window activate notification procedure.}
  702. {    Pass nil to disable it.}
  703.  
  704.     procedure SetDWindowNotify;
  705. {$IFC not singleDisplay}
  706.         var
  707.             dInfo: DIHAndle;
  708. {$ENDC}
  709.  
  710.     begin
  711.         if theWind = nil then            { reset window creation default }
  712.             d_activate := p
  713.         else
  714.             begin
  715. {$IFC singleDisplay}
  716.                 if (ISDWindow(theWind)) then
  717.                     dActivate := p;
  718. {$ELSEC}
  719.                 dInfo := GetDInfo(theWind);
  720.                 if dInfo <> nil then
  721.                     dInfo^^.dActivate := p;
  722. {$ENDC}
  723.             end;
  724.     end;
  725.  
  726. {    Set display window autoflush characteristics}
  727.  
  728.     procedure SetDWindowFlush;
  729.  
  730. {$IFC not singleDisplay}
  731.         var
  732.             dInfo: DIHandle;
  733. {$ENDC}
  734.  
  735.     begin
  736.         if maxText > longint(32767) then
  737.             maxText := 32767;
  738.         if maxText < d_loMaxText then
  739.             maxText := d_loMaxText;
  740.         if flushAmt < d_loFlushAmt then
  741.             flushAmt := d_loFlushAmt;
  742.         if theWind = nil then
  743.             begin            { reset window creation defaults }
  744.                 d_maxText := maxText;
  745.                 d_flushAmt := flushAmt;
  746.             end
  747.         else
  748.             begin
  749. {$IFC singleDisplay}
  750.                 if (IsDWindow(theWind)) then
  751.                     begin
  752.                         dMaxText := maxText;
  753.                         dFlushAmt := flushAmt;
  754.                     end;
  755. {$ELSEC}
  756.                 dInfo := GetDInfo(theWind);
  757.                 if dInfo <> nil then
  758.                     begin
  759.                         dInfo^^.dMaxText := maxText;
  760.                         dInfo^^.dFlushAmt := flushAmt;
  761.                     end;
  762. {$ENDC}
  763.             end;
  764.     end;
  765.  
  766. {    Set which display window is to be used for output.  If theWind}
  767. {    is nil, output is turned off.  If theWind is not a legal display}
  768. {    window, nothing is done.}
  769.  
  770.     procedure SetDWindow;
  771.  
  772.     begin
  773.         if (theWind = nil) or IsDWindow(theWind) then
  774.             curDispWind := theWind;
  775.     end;
  776.  
  777. {    Get the WindowPtr of the current output display window.  If}
  778. {    output is turned off, this will be nil.}
  779.  
  780.     procedure GetDWindow;
  781.  
  782.     begin
  783.         theWind := curDispWind;
  784.     end;
  785.  
  786. {    Flush text from the window and readjust the display.}
  787.  
  788.     procedure FlushDWindow;
  789.  
  790.     begin
  791.         if IsDWindow(theWind) then
  792.             begin
  793.                 SyncGlobals(theWind);
  794.                 TESetSelect(longint(0), byteCount, dispTE);    { select text }
  795.                 TEDelete(dispTE);                                { clobber it }
  796.                 OverhaulDisplay;
  797.             end;
  798.     end;
  799.  
  800. {    Create and initialize a display window and the associated data}
  801. {    structures, and return the window pointer.  Install window in}
  802. {    list of display windows.}
  803.  
  804.     procedure SetupDWindow;
  805.  
  806.         var
  807.             r: Rect;
  808.             savePort: GrafPtr;
  809. {$IFC not singleDisplay}
  810.             dInfo: DIHandle;
  811. {$ENDC}
  812.             dummy: Boolean;
  813.  
  814.     begin
  815.         dummy := SkelWindow(dispWind, @Mouse, nil, @Update, @Activate, nil, @Clobber, nil, false);
  816.     { the window }
  817.         { mouse click handler }
  818.         { key clicks are ignored }
  819.         { window updating procedure }
  820.         { window activate/deactivate procedure }
  821.         { TransSkel hides window if no close proc }
  822.         { (generates deactivate event) }
  823.         { window disposal procedure }
  824.         { no idle proc }
  825.         { irrelevant since no idle proc }
  826.  
  827. {    Build the scroll bar.  Make sure the borders overlap the}
  828. {    window frame and the frame of the grow box.}
  829.  
  830.         CalcScrollRect(r);
  831.         dispScroll := NewControl(dispWind, r, '', true, 0, 0, 0, scrollBarProc, longint(0));
  832.  
  833. {    Create the TE record used for text display.  Use defaults for}
  834. {    display characteristics.  Setting window style overhauls}
  835. {    display, so can cancel and update event pending for the window.}
  836.  
  837.         CalcEditRect(r);
  838.         dispTE := TENew(r, r);
  839.  
  840. {$IFC not singleDisplay}
  841. {    Get new information structure, attach to list of known display}
  842. {    windows.}
  843.  
  844.         dInfo := DIHandle(NewHandle(sizeof(DisplayInfo)));
  845.  
  846.         dInfo^^.dNext := dwList;
  847.         dwList := dInfo;
  848.         dInfo^^.dWind := dispWind;
  849.         dInfo^^.dScroll := dispScroll;
  850.         dInfo^^.dTE := dispTE;
  851. {$ENDC}
  852.  
  853.         SetDWindowNotify(dispWind, d_activate);
  854.         SetDWindowFlush(dispWind, d_maxtext, d_flushAmt);
  855.         SetDWindowStyle(dispWind, d_font, d_size, d_wrap, d_just);
  856.  
  857. {    Make window current display output window}
  858.  
  859.         SetDWindow(dispWind);
  860.     end;
  861.  
  862. {    Create and initialize a display window and the associated data}
  863. {    structures, and return the window pointer.  Install window in}
  864. {    list of display windows.  In single-window mode, disallow}
  865. {    creation of a new window if one already exists.}
  866.  
  867. {    The parameters are similar to those for NewWindow.  See Inside}
  868. {    Macintosh.}
  869.  
  870.     function NewDWindow;
  871.  
  872.     begin
  873. {$IFC singleDisplay}
  874.         if dispWind <> nil then
  875.             NewDWindow := nil
  876.         else
  877. {$ENDC}
  878.             begin
  879.                 dispWind := NewWindow(nil, bounds, title, visible, documentProc, behind, goAway, refCon);
  880.                 SetUpDWindow;
  881.                 NewDWindow := dispWind;
  882.             end;
  883.     end;
  884.  
  885. {    Create and initialize a display window (using a resource) and}
  886. {    the associated data structures, and return the window pointer.}
  887. {    Install window in list of display windows.  In single-window}
  888. {    mode, disallow creation of a new window if one already exists.}
  889.  
  890. {    The parameters are similar to those for GetNewWindow.  See Inside}
  891. {    Macintosh.}
  892.  
  893.     function GetNewDWindow;
  894.  
  895.     begin
  896. {$IFC singleDisplay}
  897.         if dispWind <> nil then
  898.             GetNewDWindow := nil
  899.         else
  900. {$ENDC}
  901.             begin
  902.                 dispWind := GetNewWindow(resourceNum, nil, behind);
  903.                 SetUPDWindow;
  904.                 GetNewDWindow := dispWind;
  905.             end;
  906.     end;
  907.  
  908. { ------------------------------------------------------------ }
  909. {                        Output Routines                            }
  910. { ------------------------------------------------------------ }
  911.  
  912.  
  913. {}
  914. {    Write text to display area if output is on (curDispWind != nil).}
  915. {    DisplayText is the fundamental output routine.  All other}
  916. {    output calls map (eventually) to it.}
  917.  
  918. {    First check whether the insertion will cause overflow and flush}
  919. {    out some stuff if so.  Insert new text at the end, then test}
  920. {    whether lines must be scrolled to get the new stuff to show up.}
  921. {    If yes, then do the scroll.  Set values of scroll bar properly}
  922. {    and highlight as appropriate.}
  923.  
  924. {    The current port is preserved.  Since all output calls end up}
  925. {    here, it's the only output routine that has to save the port}
  926. {    and check whether output is on.}
  927.  
  928.     procedure DisplayText;
  929.  
  930.         var
  931.             nLines, dispLines, topLines, scrollLines, lHeight: integer;
  932.         { number of lines in TERec }
  933.         { number of lines displayable in window }
  934.         { number of lines currently scrolled off top }
  935.         { number of lines to scroll up }
  936.             r: Rect;
  937.             savePort: GrafPtr;
  938.             dTE: TEHandle;
  939.  
  940.     begin
  941.         if curDispWind <> nil then
  942.             begin
  943.                 GetPort(savePort);
  944.                 SetPort(curDispWind);
  945.                 SyncGlobals(curDispWind);
  946.                 dTE := dispTE;
  947.  
  948.                 if dTE^^.teLength + len > dMaxText then    { check overflow }
  949.                     begin
  950.                         FlushDWindow(dispWind, dFlushAmt);
  951.                         DisplayString('(autoflush occurred)');
  952.                     end;
  953.                 lHeight := dTE^^.lineHeight;
  954.                 TESetSelect(longint(32767), longint(32767), dTE);
  955.                 TEInsert(theText, len, dTE);
  956.                 r := dTE^^.viewRect;
  957.                 nLines := dTE^^.nLines;
  958.                 dispLines := (r.bottom - r.top) div lHeight;
  959.                 topLines := LinesOffTop;
  960.                 scrollLines := nLines - (topLines + dispLines);
  961.                 if scrollLines > 0 then                                 { must scroll up }
  962.                     TEScroll(0, -lHeight * scrollLines, dTE);            { scroll up }
  963.                 topLines := nLines - dispLines;
  964.                 if (topLines >= 0) and (GetControlMaximum(dispScroll) <> topLines) then
  965.                     begin
  966.                         SetControlMaximum(dispScroll, topLines);
  967.                         SetControlValue(dispScroll, topLines);
  968.                     end;
  969.                 HiliteScroll;
  970.                 SetPort(savePort);
  971.             end;
  972.     end;
  973.  
  974. {    Derived output routines:}
  975.  
  976. {    DisplayString    Write (Pascal) string}
  977.  
  978. {    DisplayLong        Write value of long integer}
  979. {    DisplayInt        Write value of integer}
  980. {    DisplayChar        Write character}
  981.  
  982. {    DisplayHexLong    Write value of long integer in hex (8 digits)}
  983. {    DisplayHexInt    Write value of integer in hex (4 digits)}
  984. {    DisplayHexChar    Write value of character in hex (2 digit)}
  985.  
  986. {    DisplayBoolean    Write boolean value}
  987. {    DisplayLn        Write carriage return}
  988.  
  989.     procedure DisplayString;
  990.  
  991.         var
  992.             myPtr: Ptr;
  993.  
  994.     begin
  995.         myPtr := Ptr(longint(@theStr) + 1);
  996.         DisplayText(myPtr, longint(length(theSTr)));
  997.     end;
  998.  
  999.     procedure DisplayLong;
  1000.  
  1001.         var
  1002.             s: Str255;
  1003.  
  1004.     begin
  1005.         NumToString(l, s);
  1006.         DisplayString(s);
  1007.     end;
  1008.  
  1009.     procedure DisplayInt;
  1010.  
  1011.     begin
  1012.         DisplayLong(longint(i));
  1013.     end;
  1014.  
  1015.     procedure DisplayChar;
  1016.  
  1017.         var
  1018.             myPtr: Ptr;
  1019.  
  1020.     begin
  1021.         myPtr := @c;
  1022.         myPtr := Ptr(longint(myPtr) + 1);
  1023.         DisplayText(myPtr, longint(1));
  1024.     end;
  1025.  
  1026.     procedure DisplayLn;
  1027.  
  1028.     begin
  1029.         DisplayChar(char(13));
  1030.     end;
  1031.  
  1032.     procedure DisplayBoolean;
  1033.  
  1034.     begin
  1035.         if b then
  1036.             DisplayString('True')
  1037.         else
  1038.             DisplayString('False');
  1039.     end;
  1040.  
  1041.     procedure HexByte (value: integer);    {value should be 0..15}
  1042.     begin
  1043.         if value < 10 then
  1044.             DisplayChar(char(value + integer('0')))
  1045.         else
  1046.             DisplayChar(char(value + (integer('a') - 10)));
  1047.     end;
  1048.  
  1049.     procedure DisplayHexChar;
  1050.  
  1051.     begin
  1052.         HexByte(integer(BitAnd(BitShift(longint(c), -4), $0000000f)));
  1053.         HexByte(integer(BitAnd(longint(c), $0000000f)));
  1054.     end;
  1055.  
  1056.     procedure DisplayHexInt;
  1057.  
  1058.     begin
  1059.         DisplayHexChar(char(BitAnd(BitShift(longint(i), -8), $000000ff)));
  1060.         DisplayHexChar(char(BitAnd(longint(i), $000000ff)));
  1061.     end;
  1062.  
  1063.     procedure DisplayHexLong;
  1064.  
  1065.     begin
  1066.         DisplayHexInt(Integer(BitAnd(BitShift(l, -16), $0000ffff)));
  1067.         DisplayHexInt(integer(LoWord(l)));
  1068.     end;
  1069.  
  1070.     procedure TransDisplayInit;
  1071.  
  1072.     begin
  1073.  
  1074. {    Default values for display window characteristics}
  1075.  
  1076.         d_font := monaco;        { default font              }
  1077.         d_size := 9;                { default pointsize         }
  1078.         d_wrap := 0;                { default word wrap (on)    }
  1079.         d_just := teJustLeft;    { default justification     }
  1080.         d_maxText := 30000;    { default max text allowed  }
  1081.         d_flushAmt := 25000;    { default autoflush amount  }
  1082.         d_activate := nil;        { default notification proc }
  1083.  
  1084. {    Lowest allowable values for autoflush characteristics}
  1085.  
  1086.         d_loMaxText := 100;
  1087.         d_loFlushAmt := 100;
  1088.  
  1089. {    dwList points to a list of structures describing the known display}
  1090. {    windows.}
  1091.  
  1092. {    curDispWind is the current output window.}
  1093. {    If curDispWind = nil, output is currently turned off.}
  1094.  
  1095. {$IFC not singleDisplay}
  1096.         dwList := nil;
  1097. {$ENDC}
  1098.         dispWind := nil;
  1099.         curDispWind := nil;
  1100.     end;
  1101. end.